var gamejs = require("gamejs");
var mapModule = require("js/map");

/**
 * Match : an object that stores all the match info: credits, health points,
 * score and the map.
 */

/**
 * Creates a match.
 * 
 * @constructor
 */
var Match = exports.Match = function() {
	this.credit = 300;
	this.health = 50;
	this.inGame = true;
	this.score = 0;
	
	this.mapSurface = new gamejs.Surface(MAP_WIDTH, MAP_HEIGHT);
};

/**
 * Returns the map used by this match.
 * 
 * @return {Map} The Map object used by this match.
 * @throws {ReferenceError} If the map isn't assigned yet.
 */
Match.prototype.getMap = function() {
	if(this.map) {
		return this.map;
	}
	else {
		throw new ReferenceError("Map not assigned.");
	}
};

/**
 * Sets the map for this match.
 * 
 * @param {Map} map The Map object to use in this match.
 * @throws {TypeError} If map isn't a Map object.
 */
Match.prototype.setMap = function(map) {
	if(! map instanceof mapModule.Map) {
		throw new TypeError("map isn't a Map object");
	}
	this.map = map;
};

/**
 * Returns the player's credit.
 * 
 * @return {number} The amount of the player's credit.
 */
Match.prototype.getCredit = function() {
	return this.credit;
};

/**
 * Returns the score reached by the player in this match.
 * 
 * @return {number} The score.
 */
Match.prototype.getScore = function() {
	return this.score;
};

/**
 * Returns the planet health.
 * 
 * @return {number} The number of health points remaining to the planet.
 */
Match.prototype.getHealth = function() {
	return this.health;
};

/**
 * Checks if the player is in game.
 * 
 * @returns {boolean} False if the player has lost, true otherwise.
 */
Match.prototype.isInGame = function() {
	return this.onGame;
};

/**
 * Decreases health of one or of the given amount, it also returns
 * the remaining health.
 *
 * @param {undefined|number} hitpoint Removes one health point if undefined, the given amount otherwise.
 * @return {number} The remaining health points.
 * @throws {TypeError} If hitpoint is defined but isn't a number.
 * @throws {RangeError} If hitpoint is lesser than zero.
 */
Match.prototype.decreaseHealth = function(hitpoint) {
	if(typeof hitpoint != "number" || isNaN(hitpoint)) {
		if(typeof hitpoint == "undefined") {
			this.health--;
		}
		else {
			throw new TypeError("hitpoint isn't a number or is NaN");
		}
	}
	else {
		if(hitpoint >= 0) {
			this.health -= hitpoint;
		}
		else {
			throw new RangeError("hitpoint is lesser than zero");
		}
	}
	
	if(this.health <= 0) {
		//there aren't more health points, player lost
		this.health = 0;
		this.inGame = false;
	}
	
	return this.health;
};

/**
 * Changes the credit by the given amount, it also returns the new credit.
 *
 * @param {number} amount The amount of the credit change.
 * @return {number} The new credit points.
 * @throws {TypeError} If amount isn't a number or is NaN.
 * @throws {RangeError} If there aren't enough credit.
 */
Match.prototype.changeCredit = function(amount) {
	if(typeof amount != "number" || isNaN(amount)) {
		throw new TypeError("amount isn't a number or is NaN");
	}
	
	if((amount < 0) && ( ! this.hasCredit(-amount))) {
		throw new RangeError("Not enough credit");
	}
		
	this.credit += amount;
	
	return this.credit;
};

/**
 * Checks if player has enough credits.
 *
 * @param {number} amount The amount of the credits to check.
 * @return {boolean} True if the player has at least the given
 * amount of credits, false otherwise.
 * @throws {TypeError} If amount isn't a number or is NaN.
 * @throws {RangeError} If amount is lesser than zero.
 */
Match.prototype.hasCredit = function(amount) {
	if(typeof amount != "number" || isNaN(amount)) {
		throw new TypeError("amount isn't a number or is NaN");
	}
	
	if(amount < 0) {
		throw new RangeError("amount is lesser than zero");
	}
	
	return this.credit >= amount;
};

/**
 * Changes the score by the given amount, it also returns the new score.
 *
 * @param {number} amount The amount of the score change.
 * @return {number} The new score.
 * @throws {TypeError} If amount isn't a number or is NaN.
 * @throws {RangeError} If with this amount the score become negative.
 */
Match.prototype.changeScore = function(amount) {
	if(typeof amount != "number" || isNaN(amount)) {
		throw new TypeError("amount isn't a number or is NaN");
	}
	
	if((this.score + amount) < 0) {
		throw new RangeError("amount makes score lesser than zero");
	}
		
	this.score += amount;
	
	return this.score;
};

/**
 * Updates the data in the game.
 * 
 * @param {number} msDuration The time past from the last call, in ms.
 */
Match.prototype.update = function(msDuration) {
	if(this.map) {
		this.map.update(msDuration);
	}
};

/**
 * Draws the map and the overlay information on the given surface.
 * 
 * @param {gamejs.Surface} The Surface object where to draw.
 */
Match.prototype.draw = function(surface) {
	if(this.map) {
		this.map.draw(this.mapSurface);
	}
	else {
		this.mapSurface.fill("#000000");
	}
	//draws the map in the correct position
	surface.blit(this.mapSurface, [WIDTH_OFFSET, HEIGHT_OFFSET]);
	
	//draws/writes the overlay information
};